#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>
#include <math.h>
#include <time.h>

#define NUM_THREADS 4

typedef struct {
    long long points_per_thread;
    long long hits;
} ThreadData;

void* monte_carlo(void* arg) {
    ThreadData* data = (ThreadData*)arg;
    unsigned int seed = time(NULL) + pthread_self();
    long long hits = 0;
    
    for (long long i = 0; i < data->points_per_thread; i++) {
        double x = (double)rand_r(&seed) / RAND_MAX * 2.0 - 1.0;
        double y = (double)rand_r(&seed) / RAND_MAX * 2.0 - 1.0;
        
        if (x*x + y*y <= 1.0) {
            hits++;
        }
    }
    
    data->hits = hits;
    return NULL;
}

int main() {
    long long total_points;
    pthread_t threads[NUM_THREADS];
    ThreadData thread_data[NUM_THREADS];
    struct timeval start, end;
    
    printf("请输入采样点数(1024-65536): ");
    scanf("%lld", &total_points);
    
    if (total_points < 1024 || total_points > 65536) {
        printf("采样点数必须在1024到65536之间\n");
        return 1;
    }
    
    long long points_per_thread = total_points / NUM_THREADS;
    long long remaining_points = total_points % NUM_THREADS;
    
    // 分配点数给各线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_data[i].points_per_thread = points_per_thread;
        if (i < remaining_points) {
            thread_data[i].points_per_thread++;
        }
        thread_data[i].hits = 0;
    }
    
    gettimeofday(&start, NULL);
    
    // 创建线程
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_create(&threads[i], NULL, monte_carlo, &thread_data[i]);
    }
    
    // 等待线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    
    gettimeofday(&end, NULL);
    
    // 计算总命中数
    long long total_hits = 0;
    for (int i = 0; i < NUM_THREADS; i++) {
        total_hits += thread_data[i].hits;
    }
    
    // 计算π值
    double pi_estimate = 4.0 * total_hits / total_points;
    
    // 计算执行时间(毫秒)
    long seconds = end.tv_sec - start.tv_sec;
    long microseconds = end.tv_usec - start.tv_usec;
    double elapsed = seconds * 1000.0 + microseconds / 1000.0;
    
    // 输出结果
    printf("总采样点数: %lld\n", total_points);
    printf("圆内点数: %lld\n", total_hits);
    printf("π的估计值: %.6f\n", pi_estimate);
    printf("计算耗时: %.3f 毫秒\n", elapsed);
    
    return 0;
}